<?php

namespace app\company\controller;

use app\common\controller\CompanyController;
use app\common\enum\order\CheckStatus;
use app\common\enum\order\GoodsType;
use app\common\enum\order\OrderType;
use app\common\enum\purchase\OrderType as PurchaseOrderType;
use app\common\enum\purchase\OrderStatus as PurchaseStatus;
use app\common\enum\order\OrderStatus;
use app\common\exception\BaseException;
use app\common\model\CompanyWarehouse;
use app\common\model\Dealer;
use app\common\model\DealerGoodsSpec;
use app\common\model\DealerGoods;
use app\common\model\Refund;
use app\common\model\Salesman;
use app\common\model\Store;
use app\common\service\annotation\ControllerAnnotation;
use app\common\service\annotation\NodeAnnotation;
use app\company\model\CompanyOrder;
use app\company\model\CompanyOrderDetail;
use app\company\model\DealerOrder;
use app\company\model\DealerOrderDetail;
use app\Request;
use think\App;
use think\response\Json;
use jianyan\excel\Excel;
use  app\company\controller\Order as  OrderController;

/**
 * @ControllerAnnotation(title="回库单管理")
 */
class ReturnOrder extends CompanyController
{
    private mixed $typeArr = [
        'CG' => 1, // 采购入库单
        'XT' => 2, // 销退入库单
    ];
    /**
     * @var array|int|mixed
     */
    private mixed $type;

    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->model = new CompanyOrder();
        $this->type = $app->request->param('type') ?? 0;
        $this->importHeader    = [
            '*订单号',
            '*下单时间',
            '*经销商',
            '*业务员',
            '*门店名称',
            '是否自提(1否,2是)',
            '*商品名称',
            '*商品条码',
            '*单位类型(1小单位,2大单位,3中单位)',
            '*结算方式(1现结,2账期,3预存款)',
            '*数量',
            '*销售单价',
            '*下单价',
            
            '整单备注',
            '明细备注'
        ];
        $this->defaultTemplate = [
            'order_no',
            'create_time',
            'dealer_name',
            'salesman_name',
            'store_name',
            'is_self_order',
            'goods_name',
            'code69',
            'unit_type',
            'receive_type',
            'num',
            'sale_price',
            'true_price',
            'order_remark',
            'detail_remark'
        ];
        $this->fileName        = '退货单导入模版';
    }

    /**
     * @NodeAnnotation(title="订单")
     * @return Json
     * @throws \think\db\exception\DbException
     */
    public function list(): Json
    {
        list($limit, $where) = $this->buildSearchParams();
        if (!in_array($this->type, $this->typeArr)) $where[] = ['id', '<', 0];
        if ($this->type == $this->typeArr['XT']) {
            $list = $this->xtList($limit, $where);
        } else {
            $list = $this->cgList($limit, $where);
        }
        return $this->success($list);
    }

    /**
     * @param $limit
     * @param $where
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    private function xtList($limit, $where): \think\Paginator
    {
        return $this->model->with([
            'detail'   => function ($query) {
                $query->with([
                    'goods'     => function ($query) {
                        $query->field('id,image,name,code69')->withTrashed();
                    },
                    'goodsSpec' => function ($query) {
                        $query->field('id,image,name,sku,unit')->withTrashed();
                    },
                    'warehouse'
                ]);
            },
            'store'    => function ($query) {
                $query->field('id,name');
            },
            'dealer'   => function ($query) {
                $query->field('id,name');
            },
            'salesman' => function ($query) {
                $query->field('id,rename,phone');
            }
        ])->where('order_type', OrderType::RETURN)
            ->where($where)
            ->where('pid', '<>', 0)
            ->where($this->defaultWhere)
            ->where('check_status', '=', 2)
            ->order($this->sort)
            ->paginate($limit)->each(function ($item) {
                $item->goods_num = round(array_sum(array_column($item->detail->toArray(), 'num')), 2);
                $item->qs_money = round(array_sum(array_column($item->detail->toArray(), 'total_price')), 2);
            });
    }

    /**
     * @param $limit
     * @param $where
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     */
    private function cgList($limit, $where): \think\Paginator
    {
        $where[] = ['order_type', '=', PurchaseOrderType::CG];
        if (!empty($where['order_status'])) {
            if (!in_array($where['order_status'], [PurchaseStatus::PASS, PurchaseStatus::PUT_IN])) {
                $where[] = ['order_status', '<', 0];
            }
        } else {
            $where[] = ['order_status', 'in', PurchaseStatus::PASS . ',' . PurchaseStatus::PUT_IN];
        }
        return (new DealerOrder())->with([
            'dealer' => function ($query) {
                $query->field('id,name');
            },
            'supplier' => function ($query) {
                $query->field('id,name');
            },
            'warehouse' => function ($query) {
                $query->field('id,name');
            },
            'detail' => function ($query) {
                $query->with([
                    'goods'     => function ($query) {
                        $query->field('id,image,name')->withTrashed();
                    },
                    'spec'     => function ($query) {
                        $query->field('id,image,name,unit')->withTrashed();
                    },
                ]);
            },
        ])->where($where)->where($this->defaultWhere)->order($this->sort)->paginate($limit)->each(function ($item, $key) {
            $item->goods_num = round(array_sum(array_column($item->detail->toArray(), 'real_num')), 2);
            $item->qs_money = round(array_sum(array_column($item->detail->toArray(), 'purchase_total_price')), 2);
        });
    }

    /**
     * @NodeAnnotation(title="签收")
     * @param Request $request
     * @return Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function check(Request $request): Json
    {
        $this->checkPost();
        $post = $request->post();
        if (empty($post['type']) || !in_array($post['type'], $this->typeArr) || empty($post['id'])) return $this->error('当前请求参数非法！');
        if ($post['type'] == $this->typeArr['CG']) {
            $model = new DealerOrder();
            $detailModel = new DealerOrderDetail();
        } else {
            $model = $this->model;
            $detailModel = new CompanyOrderDetail();
        }
        $info = $model->find($post['id']);
        if ($info->isEmpty()) return $this->error('订单不存在');
        try {
            $this->model->transaction(function () use ($model, $post, $detailModel, $info) {
                $detail = json_decode($post['detail'], true);
                $detailModel->saveAll($detail);
                $goodsModel = new DealerGoods();
                $specModel = new DealerGoodsSpec();
                $specData = $detailModel->field('id,dealer_goods_id,dealer_goods_spec_id,real_num')
                                        ->where('id', 'in', array_column($detail, 'id'))
                                        ->select()->toArray();
                array_map(function ($value) use ($specModel, $goodsModel) {
                    $specModel->where('id', $value['dealer_goods_spec_id'])
                        ->inc('stock', $value['real_num'])
                        ->save();
                    // 2024.12.02 更新出库字段
                    // 计算商品的比例增加至商品的库内库存、售卖库存
                    $specInfo = $specModel->where('id', $value['dealer_goods_spec_id'])->withTrashed()->find();
                    if (!$specInfo['ratio']) throw new BaseException(['message' => $specInfo['name'] . '--商品规格比例不能为0']);
                    if (!$value['real_num']) throw new BaseException(['message' => $specInfo['name'] . '--商品数量不能为0']);
                    $goodsModel->where('id', $value['dealer_goods_id'])
                        ->inc('sales_stock', $value['real_num'] * $specInfo['ratio'])
                        ->inc('warehouse_stock', $value['real_num'] * $specInfo['ratio'])->save();
                }, $specData);

                if ($post['type'] == $this->typeArr['CG']) {
                    $info->save(['order_status' => PurchaseStatus::PUT_IN]);
                } else {
                    $info->save(['order_status' => OrderStatus::FINISH]);
                }
            });
        } catch (\Exception $e) {
            return $this->error('入库失败:' . $e->getMessage() . '--' . $e->getLine());
        }
        return $this->success('入库成功');
    }

    /**
     * @NodeAnnotation(title="上架")
     */
    public function putAway(Request $request) {}


    /**
     * @NodeAnnotation(title="导入")
     * @throws BaseException
     */
    public function import(Request $request): Json
    {
        $this->checkPost();
        $file = $request->file('file');
        if (!$file) return $this->error('请上传文件！');
        // 保存文件到临时目录
        $savePath = $file->move('storage' . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR);
        // 获取文件的完整路径
        $savePath = $savePath->getPathname();
        $this->model->startTrans();
        try {
            $data = Excel::import($savePath, 1, false, 'Xlsx', './storage/temp/excelImg/');
            if (!$data) throw new BaseException(['message' => '文件内容为空！']);
            if (!$this->importHeader) throw new BaseException(['message' => '请联系管理设置文件模版！']);
            if (array_filter($data[0]) != $this->importHeader) throw new BaseException(['message' => '文件模版错误！']);
            // 去掉表头
            unset($data[0]);
            $data = array_filter($data);

            $this->dealOrder($data);
        } catch (\Exception $e) {
            @unlink($savePath);
            $this->model->rollback();
            return $this->error('导入失败' . $e->getMessage());
        }
        @unlink($savePath);
        $this->model->commit();
        return $this->success('导入成功！');
    }
    public function dealOrder(mixed $data): void
    {
        if (empty($data)) throw new BaseException(['message' => '文件内容为空！']);
        $orders = array_map(function ($vo) {
            $fields = $this->defaultTemplate;
            $data   = array_combine($fields, $vo);
            // 验证表格中的值
            $rule = [
                'order_no|订单号'       => 'require',
                'create_time|下单时间'  => 'require',
                'dealer_name|经销商'    => 'require',
                'salesman_name|业务员'  => 'require',
                'store_name|门店名称'   => 'require',
                'goods_name|商品名称'   => 'require',
                'code69|商品条码'       => 'require',
                'unit_type|单位类型'    => 'require',
                'receive_type|结算方式' => 'require',
                'num|数量'              => 'require',
                'sale_price|销售单价'   => 'require',
                'true_price|下单价'     => 'require',
            ];
            $this->validate($data, $rule);
            return $data;
        }, $data);
        // 订单号去重
        $orderNos = array_unique(array_column($orders, 'order_no'));
        foreach ($orderNos as $orderNo) {
            // 匹配订单
            $filteredArray = array_filter($orders, function ($item) use ($orderNo) {
                return $item['order_no'] === $orderNo;
            });
            // 重组
            $orderData = array_values($filteredArray);
            //                        halt($orderData);
            // 订单公共信息
            $commonOrder              = [
                'company_id'    => $this->companyId,
                'order_no'      => $orderNo,
                'create_time'   => strtotime($orderData[0]['create_time']),
                'receive_type'  => $orderData[0]['receive_type'] ?? 1,
                'remark'        => $orderData[0]['order_remark'] ?? '',
                'is_self_order' => $orderData[0]['is_self_order'] ?? 1,
                'check_status'  => CheckStatus::YES_CHECK,
                'order_channel' => 1,
                'back_type'=>1,
            ];
            $commonOrder['dealer_id'] = Dealer::where('company_id', $this->companyId)
                ->where('name', $orderData[0]['dealer_name'])
                ->value('id');
            if (!$commonOrder['dealer_id']) throw new BaseException(["message" => "经销商【{$orderData[0]['dealer_name']}】不存在！"]);

            $commonOrder['salesman_id'] = Salesman::where('company_id', $this->companyId)
                ->where('rename', $orderData[0]['salesman_name'])
                ->value('id');
            if (!$commonOrder['salesman_id']) throw new BaseException(["message" => "业务员【{$orderData[0]['salesman_name']}】不存在！"]);

            $commonOrder['store_id'] = Store::where('company_id', $this->companyId)
                ->where('name', $orderData[0]['store_name'])
                ->value('id');
            if (!$commonOrder['store_id']) throw new BaseException(["message" => "门店【{$orderData[0]['store_name']}】不存在！"]);

            // 主订单
            $order = $commonOrder;
            // 订单金额
            $order_amount = 0;
            foreach ($orderData as $key => $value) {
                $order_amount+= $value['sale_price']* $value['num'];
            };
            $order['order_amount'] =  sprintf("%.2f", $order_amount);
            // 退款金额
            $order['return_amount'] = sprintf("%.2f", $order_amount);
            // 子订单
            $info       = $commonOrder;
            $childOrder = [];
            // 根据类型组装子订单
            $goodsType = 3;
            // 销售单
            $xsOrderArray = array_filter($orderData, function ($item) {
                return in_array($item['goods_type'], [GoodsType::SALE, GoodsType::GIFT]);
            });


            // 回库单

            $info['order_no']      = $order['order_no'] . '-' . OrderType::RETURN;
            $info['order_type']    = OrderType::RETURN;
            $info['order_amount']  = array_sum(array_column($orderData, 'return_amount'));
            $info['return_amount'] = $info['order_amount'];
            $info['unsay_amount']  = $info['order_amount'];
            // 组装退款单信息
            $returnAmountArray = array_filter($orderData, function ($item) {
                return in_array(3, [GoodsType::RETURN_GOODS, GoodsType::CHANGE_GOODS]);
            });
            $details           = array_map(function ($vo) use ($info) {
                $detail                    = [
                    'goods_type'  => $vo['goods_type'],
                    'true_price'  => $vo['true_price'],
                    'num'         => $vo['num'],
                    'real_num'    => $vo['num'],
                    'total_price' => $vo['order_amount'],
                    'remark'      => $vo['detail_remark']
                ];
                $detail['dealer_goods_id'] = DealerGoods::where('dealer_id', $info['dealer_id'])
                    ->where('name', $vo['goods_name'])
                    ->value('id') ?? '';
                if (!$detail['dealer_goods_id']) throw new BaseException(["message" => "经销商【{$vo['dealer_name']}】商品【{$vo['goods_name']}】不存在！"]);

                $detail['dealer_goods_spec_id'] = DealerGoodsSpec::where(
                    'dealer_goods_id',
                    $detail['dealer_goods_id']
                )
                    ->where('unit_type', $vo['unit_type'])
                    ->value('id') ?? '';
                if (!$detail['dealer_goods_spec_id']) throw new BaseException(["message" => "经销商【{$vo['dealer_name']}】商品【{$vo['goods_name']}】规格单位【{$vo['unit_type']}】不存在！"]);
                // TODO 仓库后期需要选择录入
                $detail['company_warehouse_id'] = CompanyWarehouse::where('company_id', $this->companyId)
                    ->value('id');
                return $detail;
            }, $returnAmountArray);

            $account        = ['return_amount' => $info['return_amount']];
            $userInfo       = ['salesman_id' => $info['salesman_id'], 'store_id' => $info['store_id']];
            $info['detail'] = $details;
            $childOrder[]   = $info;
            // 2024.11.14 生成退款单和增加金额
            $order_controller = new OrderController(new App());
            $refundData = $order_controller->dealAccountRecord($account, $userInfo);

            // 新增主订单
            $orderModel = new CompanyOrder();
            $save       = $orderModel->save($order);
            if (!$save) throw new BaseException(["message" => "订单保存失败！"]);
            // 新增子订单
            $childOrder     = array_map(function ($vo) use ($orderModel) {
                $vo['pid'] = $orderModel->id;
                return $vo;
            }, $childOrder);
            $childOrderInfo = $orderModel->saveAll($childOrder);
            // 保存退款单
            if (!empty($refundData)) {
                $companyOrderId = $orderModel->where('pid', $orderModel->id)
                    ->where('order_type', OrderType::RETURN)->value('id');
                if (!$companyOrderId) throw new BaseException(['message' => '数据错误']);
                $refundData['company_order_pid'] = $orderModel->id;
                $refundData['company_order_id']  = $companyOrderId;
                (new Refund())->save($refundData);
            }
            // 保存订单详情
            $childOrderInfo = $childOrderInfo->toArray();
            array_walk($childOrderInfo, function ($v) {
                $detail = $v['detail'];
                foreach ($detail as &$item) {
                    $item['company_order_id']  = $v['id'];
                    $item['company_order_pid'] = $v['pid'];
                }
                // 新增订单详情
                (new CompanyOrderDetail())->insertAll($detail);
            });
            // 如果对应订单内是预存款结算，需要把预存款转入冻结金额字段
            $userInfo   = ['receive_type' => $commonOrder['receive_type'], 'salesman_id' => $commonOrder['salesman_id'], 'store_id' => $commonOrder['store_id']];
            $orderMoney = array_sum(array_column($xsOrderArray, 'order_amount'));
            $order_controller->dealYc1($userInfo, $orderMoney);
        }
    }
}
